home *** CD-ROM | disk | FTP | other *** search
/ Night Owl 9 / Night Owl CD-ROM (NOPV9) (Night Owl Publisher) (1993).ISO / 015a / when33.zip / WHEN.ASM next >
Assembly Source File  |  1993-04-04  |  33KB  |  803 lines

  1.         PAGE    58,132
  2.  
  3. ; WHEN - A Terminate & Stay Resident delayed activation utility
  4. ;
  5. ; ******************************************************************
  6. ;                      L E G A L   B I T S
  7. ;
  8. ; WHEN, and all the ancillary programs in this package are my own
  9. ; work, and are copyright by that fact.  I hereby place that set in
  10. ; the public domain.  I place NO restriction of any kind on their
  11. ; use, adaptation, resale, possession or transfer.
  12. ;
  13. ; If you have a copy of this material, you have it with my blessings
  14. ; and good wishes.  May it do well by you.
  15. ;
  16. ; I accept NO contingent responsibility of any kind for the use or
  17. ; any consequence of use of this software.  If you use it, it is
  18. ; presumed that you know why and how to use it, and that you are in
  19. ; full control of all consequences of that use.
  20. ;
  21. ;                      David Hatch  M.A.C.S.
  22. ;
  23. ; Due to ethics violations that could be levied against the modifier
  24. ; of this program, THE UNKNOWN HACKER can not take any credit for bringing
  25. ; this program to full functionality by making it a re-usable TSR. 
  26. ; David Hatch's PUBLIC DOMAIN stipulation remains in full effect.
  27. ; Thanks. 
  28. ; ******************************************************************
  29. ;
  30.  
  31. ;------------------------------------------------
  32. ; macro- push all registers
  33. ;
  34. pushall macro
  35.         push ax
  36.         push bx
  37.         push cx
  38.         push dx
  39.         push ds
  40.         push es
  41.         push si
  42.         push di
  43.         push bp
  44. endm
  45.  
  46. ;------------------------------------------------
  47. ; macro- pop all registers
  48. ;
  49. popall macro
  50.         pop bp
  51.         pop di
  52.         pop si
  53.         pop es
  54.         pop ds
  55.         pop dx
  56.         pop cx
  57.         pop bx
  58.         pop ax
  59. endm
  60.  
  61. CR      EQU     0DH                    ;ASCII Carriage Return
  62. LF      EQU     0AH                    ;ASCII Line Feed
  63. BELL    EQU     07H                    ;ASCII Bell
  64. TRUE    EQU     0FFFFh
  65. FALSE   EQU     NOT TRUE
  66.  
  67. ON      EQU     TRUE
  68. OFF     EQU     FALSE
  69.  
  70. TAB     EQU     09h
  71.  
  72.  
  73. VECTORS SEGMENT AT 0000H               ;Segment for vectors
  74.         ORG     08H * 4                ;Timer interrupt
  75. TIMERV  LABEL   DWORD                  ;vector assignment
  76. VECTORS ENDS
  77.  
  78. ROMDATA SEGMENT AT 0040H               ;ROM BIOS Data area
  79.         ORG     1AH                    ;Keyboard buffer data
  80.         ;
  81.         ; ******  KEYBOARD BUFFER OPERATING ALGORITHM  ******
  82.         ;
  83.         ;In IBM's notation as used for the PC keyboard buffer,
  84.         ;a producer process will put in at the buffer TAIL, and
  85.         ;a consumer process will take out at the buffer HEAD.
  86.         ;
  87.         ;If the buffer is empty, HEAD = TAIL.  If the buffer is
  88.         ;full, HEAD = WRAP(TAIL+2).  The WRAP function applies to
  89.         ;HEAD and TAIL, and operates to make the first location
  90.         ;in the buffer logically follow the last location, so that
  91.         ;the buffer is "wrapped" conceptually into a circle.  The
  92.         ;TAIL pointer is left pointing past the last character + scan
  93.         ;entered, The HEAD pointer is left pointing at last taken.
  94.         ;
  95. KBHEAD  DW      ?                      ;Buffer HEAD pointer
  96. KBTAIL  DW      ?                      ;Buffer TAIL pointer
  97.         ORG 80h
  98. KBBUF   DW      ?                      ;Buffer data area
  99.         ORG 82h
  100. KBBEND  DW ?                           ;Buffer end(wrap) mark.
  101. ROMDATA ENDS
  102.  
  103.  
  104. CSEG    SEGMENT PARA 'CODE'
  105.         ASSUME  CS:CSEG, DS:CSEG, SS:CSEG, ES:NOTHING
  106.         ORG     100H                   ;Locate as .COM file
  107.  
  108. WHEN    PROC FAR
  109.         JMP     INIT                   ;Initialize resident & terminate.
  110.  
  111.         ; ************************************************************
  112.         ;     THIS IS SELF MODIFYING CODE - TAKE CARE IF EDITING
  113.         ; ************************************************************
  114.         ;
  115.         ; This ISR begins with a switch jump.  This is a relative jump,
  116.         ; with a dynamically reset offset.  It is well suited to ISR use,
  117.         ; as it does not change the CPU state, or require save/restore
  118.         ; operations.  It is fast, causing little overhead.
  119.         ;
  120.         ; If this code is to be modified, check VERY carefully, and try
  121.         ; to fully understand, all references to TIMEI+1. (The switch.)
  122.  
  123. TIMEI   PROC NEAR                      ;This code is changed while running.
  124.         JMP  SHORT TIME1               ;Switch jump waiting/active/inactive
  125.  
  126.         ; Operation of the ISR is over for this call. (It may be reused
  127.         ; in a later invocation.)  Exit, minimum delay, ISR is inactive.
  128.         ; This is the last switch jump setting in a sequence of 3.
  129.         ;
  130.         JMP  DWORD PTR CS:TIVOFF       ;Go to the previous ISR if inactive.
  131.  
  132.  
  133.         ; Wait for the specified time, then switch this ISR
  134.         ; from waiting to active character feeding.  This is
  135.         ; the first switch jump setting in a sequence of 3.
  136.         ;
  137. WAIT1:
  138.         PUSHF
  139.         PUSH    AX                     ;Save registers
  140.         PUSH    CX
  141.         PUSH    DX
  142.         MOV     AH,0                   ;Function 0 of Interrupt 1AH
  143.         INT     1AH                    ;Read time of day in ticks.
  144.         CMP     CX,CS:WHENHI           ;If in the requested hour,
  145.         JNE     WAIT2                  ;Then:
  146.         MOV     AX,CS:WHENLO           ;Consider low word of time,
  147.         CMP     AX,DX                  ;If time has arrived,
  148.         JNE     WAIT2                  ;Then:
  149.         MOV     AL,CS:TIMESW           ;Using the assembled switch value,
  150.         MOV  CS:BYTE PTR TIMEI+1,AL    ;start the keyboard buffer load.
  151. WAIT2:
  152.         POP     DX                     ;Restore registers
  153.         POP     CX
  154.         POP     AX
  155.         POPF
  156.         JMP  DWORD PTR CS:TIVOFF       ;Now go to the previous ISR.
  157.  
  158.         ; Time is up, feed characters into keyboard buffer,
  159.         ; when done, switch ISR to inactive, doing nothing.
  160.         ; This is the second switch jump setting in this
  161.         ; sequence of 3.  This switch jump setting uses the
  162.         ; offset value as assembled in the source file.
  163. TIME1:
  164.         PUSH    AX                     ;Save registers
  165.         PUSH    BX                     ;used in this code.
  166.         PUSH    SI
  167.         PUSH    DI
  168.         PUSH    DS                     ;Save Data Segment
  169.  
  170.         ASSUME  DS:ROMDATA
  171.         MOV     AX,ROMDATA             ;Use ROM BIOS data segment
  172.         MOV     DS,AX                  ;to see keyboard buffer.
  173.         MOV     SI,CS:WHCMP            ;Point to (CS:) command string
  174.         MOV     BX,OFFSET SCANC        ;Point to (CS:) scan code table
  175.  
  176. TIME2:
  177.         MOV     DI,KBTAIL              ;Use TAIL to put in keys.
  178.         INC     DI                     ;Move DX on to the
  179.         INC     DI                     ;next buffer position.
  180.         CMP     DI,KBBEND              ;Consider buffer end, if wrap,
  181.         JL      TIME3                  ;Then:
  182.         MOV     DI,KBBUF               ;wrap to start of buffer.
  183. TIME3:
  184.         CMP     DI,KBHEAD              ;If the buffer is not full,
  185.         JE      TIMEX                  ;Then:
  186.  
  187.         MOV     AL,CS:[SI]             ;Read a character from the
  188.         INC     SI                     ;command & step over it.
  189.         OR      AL,AL                  ;If this character is the
  190.         JNE     TIME4                  ;end marker, Then:
  191.         MOV     AL,CR                  ;provide automatic CR.
  192. TIME4:
  193.         MOV     AH,AL                  ;Save a copy of character
  194.         XLAT    CS:SCANC               ;look up scan code [BX]
  195.         XCHG    AH,AL                  ;Scan code AH, ASCII in AL.
  196.         XCHG    DI,KBTAIL              ;Update TAIL, use original,
  197.         CMP     AL,','                 ;If not above the limit
  198.         JA      TIME6                  ;And:
  199.         CMP     AL,'#'
  200.         JB      TIME6                  ;Then:
  201.         MOV     AL,0
  202. TIME6:  MOV     [DI],AX                ;put keystroke in buffer.
  203.         CMP     AL,CR                  ;If this was not the end,
  204.         JNE     TIME2                  ;continue, Else:
  205.  
  206.         MOV     CS:BYTE PTR TIMEI+1,0  ;Set switch jump to inactive.
  207. TIMEX:
  208.         POP     DS                     ;Restore Data Segment
  209.         POP     DI                     ;Restore registers
  210.         POP     SI
  211.         POP     BX
  212.         POP     AX
  213.         JMP     DWORD PTR CS:TIVOFF    ;Now go to the previous ISR.
  214.  
  215.  
  216.  
  217.         ; Scan code lookup table. Index into this table with an ASCII
  218.         ; code, and receive back the scan code which would have been
  219.         ; generated by an IBM compatible keyboard for that ASCII value.
  220.         ; Position in table is ASCII code, content is scan code (decimal).
  221.  
  222. SCANC   LABEL BYTE
  223.  
  224.         ;  NUL SOH STX ETX EOT ENQ ACK BEL  BS  HT  LF  VT  FF  CR  SO  SI
  225.         DB  00, 30, 48, 46, 32, 18, 33, 34, 14, 15, 28, 37, 38, 28, 49, 24
  226.         ;
  227.         ;  DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN  EM SUB ESC  FS  GS  RS  US
  228.         DB  25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 26, 43, 27, 07, 12
  229.         ;
  230.         ;               F1  F2  F3  F4  F5  F6  F7  F8  F9  F10
  231.         ;  SPC  !   "   #   $   %   &   '   (   )   *   +   ,   -   .   /
  232.         DB  57, 02, 40, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 12, 52, 53
  233.         ;
  234.         ;   0   1   2   3   4   5   6   7   8   9   :   ;   <   =   >   ?
  235.         DB  11, 02, 03, 04, 05, 06, 07, 08, 09, 10, 39, 39, 51, 13, 52, 53
  236.         ;
  237.         ;   @   A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
  238.         DB  03, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24
  239.         ;
  240.         ;   P   Q   R   S   T   U   V   W   X   Y   Z   [   \   ]   ^   _
  241.         DB  25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 26, 43, 27, 07, 12
  242.         ;
  243.         ;   `   a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
  244.         DB  41, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38, 50, 49, 24
  245.         ;
  246.         ;   p   q   r   s   t   u   v   w   x   y   z   {   |   }   ~  DEL
  247.         DB  25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44, 26, 43, 27, 41, 00
  248.  
  249.  
  250.         ; This variable holds the original assembled value of a relative
  251.         ; jump offset, in the first instruction of this ISR.  The actual
  252.         ; running value is used as a dynamic switch, altering the function
  253.         ; of the ISR with time.  The value held here is the value used
  254.         ; to select "Time is expired, load requested command" behavior.
  255.         ;
  256. TIMESW  DB      00                     ;Time expired switch value
  257. TIMESWO DB      00                     ;Time expired switch value ORG
  258.  
  259. TIVOFF  DW      0000                   ;Previous ISR    ;offset
  260. TIVSEG  DW      0000                   ;routine addr    ;segment
  261.  
  262. WHENLO  DW      0000                   ;Time count comparison (Low)
  263. WHENHI  DW      0000                   ;Time count comparison (High)
  264.  
  265. ISKIPO  DW      OFFSET ISKIP
  266. WHCMP   DW      OFFSET WHCMD           ;Delayed command pointer
  267. WHCMD   DB      80 DUP(00)             ;Delayed command buffer
  268.  
  269.  
  270. ISKIP   DB BELL
  271.         DB "Memory Warning : Possible modification. Stay tuned!",CR,LF,BELL,'$'
  272. ID      DB 'WHEN v3.3 April 4, 1993',CR,LF,'$'
  273.  
  274. HH10    DB      '0'                    ;Tens of hours (input time)
  275. HH01    DB      '0'                    ;Units of hours (input time)
  276.         DB      ':'
  277. MM10    DB      '0'                    ;Tens of minutes (input time)
  278. MM01    DB      '0'                    ;Units of minutes (input time)
  279.         DB      ':'
  280. SS10    DB      '0'                    ;Tens of seconds (input time)
  281. SS01    DB      '0'                    ;Units of seconds (input time)
  282.         DB      "  "
  283.         DB      '$'
  284. INTER   DB      ' '                    ;Interactive mode (normally on)
  285. REAL21             LABEL  DWORD
  286. REAL21_OFS         DW     ?
  287. REAL21_SEG         DW     ?
  288.  
  289. INT21:             PUSHF                       ; Save flags
  290.                    CMP    AH,0AAH              ; Is this 'our' function?
  291.                    JE     OUR_FUNCTION
  292. OLD:               POPF                        ; Restore flags we called with
  293.                    JMP    CS:REAL21            ; Otherwise don't mess with the
  294.                                                ;   interrupt
  295.  
  296. ; Check if caller is looking for this program
  297.  
  298. OUR_FUNCTION:      
  299.                    PUSH   ES                   ; Save registers
  300.                    PUSH   CX                   ;
  301.                    push   ax
  302.                    PUSH   SI                   ;
  303.                    PUSH   DI                   ;
  304.  
  305.                    PUSH   CS                   ; Set destination to us
  306.                    POP    ES                   ;
  307.                    MOV    DI,OFFSET ID         ; Point to our ID
  308.                    MOV    CX,8                 ;
  309.                    CLD
  310.                    REPE   CMPSB                ; See if ID is us
  311.  
  312.                    POP    DI                   ; Restore registers
  313.                    POP    SI                   ;
  314.                    MOV    INTER,AL
  315.                    pop    ax
  316.                    JCXZ   ID_OK                ; If zero, ID matches
  317.                    POP    CX                   ; Reset registers
  318.                    POP    ES                   ;
  319.                    JMP    OLD                  ; And continue to DOS
  320.  
  321. ID_OK:
  322.                    pushall
  323.  
  324.                    MOV    AL,INTER
  325.                    CMP    AL,'/'
  326.                    JE     ID_OK1
  327.                    
  328.                    MOV    DX,OFFSET ID
  329.                    MOV    AH,9
  330.                    INT    21H
  331.                    MOV    DX,OFFSET ISKIP
  332.                    MOV    AH,9
  333.                    INT    21H
  334.      
  335. ID_OK1:            popall
  336.                    POP     CX                   ; Reset CX
  337.                    ADD     SP,2                 ; ES stays the same
  338.                    NOT     BX                   ; Invert BX to say we're here
  339.                    POPF
  340.                    IRET
  341.                    NOP
  342. TIMEI   ENDP
  343. ;*********************************************************************
  344. ;*                                                                   *
  345. ;*       Release memory from this point on for reuse by DOS.         *
  346. ;*                                                                   *
  347. ;*********************************************************************
  348. ;
  349. TSREND:                                ;Release from here
  350.  
  351. ENTES   DW      0000                   ;ES pointing to program's PSP
  352.  
  353. CCOUNT  DB      00                     ;Command line character count
  354.  
  355.  
  356. RESIDENT  DB 0FFH
  357. FIRSTCH   DB 002H
  358. TORG      DB 0FFH
  359. ; Initialize T.S.R. resident portion, presetting as required. This
  360. ; code is no longer present after T.S.R. is running, as this RAM
  361. ; area has been returned to DOS for other uses.
  362.  
  363. INIT:
  364.         ; Parse the command line, exit if no request present.
  365.         ; Parse time, then command request with full filespec.
  366.  
  367.         MOV     SI,0081H              ;Point to command line
  368.         MOV     AL,[SI-1]             ;Use character count of this
  369.         MOV     CCOUNT,AL             ;command line, as entered.
  370.  
  371.         ; Consume spaces, until first non-space character
  372. INIT1:
  373.         CALL    GETCH                 ;If there is a character
  374.         JC      INITL                 ;available, And:
  375.         CMP     AL,' '                ;It is not an ASCII Space,
  376.         JE      INIT1                 ;Then:
  377.         CMP     AL,'/'                ;If interactive mode is OFF
  378.         JNE     INITL                 ;Then:
  379.         MOV     INTER,AL              ;Suppress user interaction
  380.         JMP    SHORT INIT1            ;and continue to scan.
  381.  
  382. INITL:  MOV     AH,0AAH
  383.         MOV     AL,INTER
  384.         MOV     SI,OFFSET ID
  385.         XOR     BX,BX
  386.         INT     21H
  387.         PUSH    ES
  388.         MOV     ENTES,ES              ;Save register for exit
  389.         INC     BX
  390.         JZ      PARSEA
  391.         ; pointing to this program's ISR resident code.
  392.  
  393.         MOV     AX,3508H              ;Read existing interrupt
  394.         INT     21H                   ;08h vector contents
  395.         MOV     TIVOFF,BX             ;and use them as destination
  396.         MOV     TIVSEG,ES             ;pointer to previous ISR code.
  397.         MOV     AX,CS                 ;The Timer interrupt segment
  398.         MOV     DS,AX                 ;must point to this code segment,
  399.         MOV     DX,OFFSET TIMEI       ;referring to ISR entry point.
  400.         MOV     AX,2508H              ;Access interrupt 08h, routing
  401.         INT     21H                   ;via this program's handler.
  402.  
  403.  
  404.         MOV     AX,3521H              ;Read existing interrupt
  405.         INT     21H                   ;08h vector contents
  406.         MOV     REAL21_OFS,BX         ;and use them as destination
  407.         MOV     REAL21_SEG,ES         ;pointer to previous ISR code.
  408.         MOV     AX,CS                 ;The Timer interrupt segment
  409.         MOV     DS,AX                 ;must point to this code segment,
  410.         MOV     DX,OFFSET INT21       ;referring to ISR entry point.
  411.         MOV     AX,2521H              ;Access interrupt 21h, routing
  412.         INT     21H                   ;via this program's handler.
  413.  
  414.  
  415.         MOV     RESIDENT,0
  416.         MOV     AL,BYTE PTR TIMEI+1   ;Read assembled branch offset
  417.         MOV     TIMESWO,AL            ;switch value & save it, then
  418.  
  419.  
  420. PARSEA: POP     ES
  421.         MOV     ENTES,ES              ;Save register for exit
  422.         CMP     RESIDENT,0
  423.         JE      FIRSTT
  424.         MOV     AL,ES:BYTE PTR TIMEI+1 ;Save time monitor entry STATUS
  425.         MOV     TORG,AL
  426. FIRSTT: MOV     AL,ES:TIMESWO         ;Read assembled branch offset org
  427.         MOV     ES:TIMESW,AL          ;switch value & save it, then
  428.         MOV     ES:BYTE PTR TIMEI+1,0 ;Kill time monitor but wait and see.
  429.  
  430.         ; Parse the command line, exit if no request present.
  431.         ; Parse time, then command request with full filespec.
  432.  
  433. PARSEB: MOV     SI,0081H              ;Point to command line
  434.         MOV     AL,[SI-1]             ;Use character count of this
  435.         MOV     CCOUNT,AL             ;command line, as entered.
  436.  
  437.         ; Consume spaces, until first non-space character
  438. PARSE1:
  439.         MOV     FIRSTCH,1
  440.         CALL    GETCH                 ;If there is a character
  441.         JC      BADT1                 ;available, And:
  442.         CMP     AL,' '                ;It is not an ASCII Space,
  443.         JE      PARSE1                ;Then:
  444.         CMP     AL,'/'                ;If interactive mode is OFF
  445.         JNE     PARSE2                ;Then:
  446.         MOV     FIRSTCH,0
  447.         MOV     INTER,AL              ;Suppress user interaction
  448.         JMP    SHORT PARSE1           ;and continue to scan.
  449.  
  450.         ; Accept HH [ :MM [ :SS ]] time specification input
  451. PARSE2:
  452.         PUSHALL
  453.         MOV     AL,INTER
  454.         CMP     AL,' '
  455.         JNE     PARSE3
  456.         MOV     AL,RESIDENT
  457.         CMP     AL,0
  458.         JNE     PARSE3
  459.         MOV     DX,OFFSET ID          ;Format the screen, and
  460.         MOV     AH,9                  ;Display the details.
  461.         INT     21H
  462. PARSE3: 
  463.         POPALL
  464.         MOV     FIRSTCH,0
  465.         MOV     AH,'2'                ;Tens of hours .LE. 2
  466.         CALL    CHNUM                 ;If valid digit,
  467.         JC      BADT1                 ;Then:
  468.         MOV     ES:HH10,AL            ;Accept Tens of hours.
  469.  
  470.         CALL    GETCH                 ;If there is a character
  471.         JC      BADTM                 ;available, Then:
  472.         MOV     AH,'9'                ;Units of hours .LE. 9
  473.         CALL    CHNUM                 ;If valid digit,
  474.         JC      BADT1                 ;Then:
  475.         MOV     ES:HH01,AL            ;Accept Units of hours.
  476.  
  477.         CALL    GETCH                 ;If there is a character
  478.         JC      BADT1                 ;available, Then:
  479.         CMP     AL,' '                ;If not the terminator,
  480.         JZ      TIMOK                 ;And:
  481.         CMP     AL,':'                ;It is a valid time
  482.         JNZ     BADTM                 ;separator, Then:
  483.  
  484.         CALL    GETCH                 ;If there is a character
  485. BADT1:  JC      BADTM                 ;available, Then:
  486.         MOV     AH,'5'                ;Tens of minutes .LE. 5
  487.         CALL    CHNUM                 ;If valid digit,
  488.         JC      BADTM                 ;Then:
  489.         MOV     ES:MM10,AL            ;Accept Tens of minutes.
  490.  
  491.         CALL    GETCH                 ;If there is a character
  492.         JC      BADTM                 ;available, Then:
  493.         MOV     AH,'9'                ;Units of minutes .LE. 9
  494.         CALL    CHNUM                 ;If valid digit,
  495.         JC      BADTM                 ;Then:
  496.         MOV     ES:MM01,AL            ;Accept Units of minutes.
  497.  
  498.         CALL    GETCH                 ;If there is a character
  499.         JC      BADTM                 ;available, Then:
  500.         CMP     AL,' '                ;If not the terminator,
  501.         JZ      TIMOK                 ;And:
  502.         CMP     AL,':'                ;It is a valid time
  503.         JNZ     BADTM                 ;separator, Then:
  504.  
  505.         CALL    GETCH                 ;If there is a character
  506.         JC      BADTM                 ;available, Then:
  507.         MOV     AH,'5'                ;Tens of seconds .LE. 5
  508.         CALL    CHNUM                 ;If valid digit,
  509.         JC      BADTM                 ;Then:
  510.         MOV     ES:SS10,AL            ;Accept Tens of seconds.
  511.  
  512.         CALL    GETCH                 ;If there is a character
  513.         JC      BADTM                 ;available, Then:
  514.         MOV     AH,'9'                ;Units of seconds .LE. 9
  515.         CALL    CHNUM                 ;If valid digit,
  516.         JC      BADTM                 ;Then:
  517.         MOV     ES:SS01,AL            ;Accept Units of seconds.
  518.         JMP    SHORT TIMOK            ;Time input is valid.
  519.  
  520.  
  521.         ; Report error in time value input
  522. BADTM:  
  523.         CMP     FIRSTCH,1
  524.         JE      BADTM0
  525.         JMP     BADTM2
  526. BADTM0: CMP     RESIDENT, 0FFH ;TRUE
  527.         JE      BADTM1
  528.         MOV     ES:BYTE PTR TIMEI+1,0 ;Kill time monitor if first time thru
  529.         MOV     TORG,0
  530.         
  531. BADTM1: JMP     EXIT
  532. BADTM2: MOV     AL,01H                ;Assign error level (this error)
  533.         MOV     DX,OFFSET TIMERR      ;Select time input error message
  534.         JMP     ERREX                 ;and exit with error display.
  535.  
  536.         ; Convert time into tick count value, which will
  537.         ; be used for comparison during the delay period.
  538.         ;
  539.         ; IBM PC time is kept in 18.2 (approx) ticks per second,
  540.         ; or more precisely 65536 (16 bit binary) per hour.
  541.         ;
  542.         ; Conversion in this program is handled by the following:
  543.         ; High word=hours(exact), Low word=(mins * 1092.25(exact))
  544.         ; plus (seconds * 18.25(approximation).
  545.  
  546. TIMOK:
  547.         MOV     BX,OFFSET ES:HH10     ;Consider hours,
  548.         CALL    ASCBIN                ;convert to binary,
  549.         MOV     ES:WHENHI,AX          ;set tick count(high).
  550.         MOV     BX,OFFSET ES:MM10     ;Consider minutes,
  551.         CALL    ASCBIN                ;convert to binary,
  552.         MOV     BX,AX                 ;copy the result.
  553.  
  554.         SHR     AX,1                  ; /2         Multiply hours
  555.         SHR     AX,1                  ; /4 (0.25)  by 1092.25 to
  556.         SHL     BX,1                  ; * 2        get ticks per
  557.         SHL     BX,1                  ; * 4        hour.
  558.         ADD     AX,BX                 ; ( Accumulation = * 4.25 )
  559.         SHL     BX,1                  ; * 8
  560.         SHL     BX,1                  ; * 16
  561.         SHL     BX,1                  ; * 32
  562.         SHL     BX,1                  ; * 64
  563.         ADD     AX,BX                 ; ( Accumulation = * 68.25 )
  564.         SHL     BX,1                  ; * 128
  565.         SHL     BX,1                  ; * 256
  566.         SHL     BX,1                  ; * 512
  567.         SHL     BX,1                  ; * 1024
  568.         ADD     AX,BX                 ; ( Accumulation = * 1092.25 )
  569.         MOV     DX,AX                 ; Save hours result.
  570.  
  571.         MOV     BX,OFFSET ES:SS10     ;Consider seconds,
  572.         CALL    ASCBIN                ;convert to binary,
  573.         MOV     BX,AX                 ;copy the result.
  574.         SHR     AX,1                  ; /2         Multiply seconds
  575.         SHR     AX,1                  ; /4 (0.25)  by 18.2 to get the
  576.         SHL     BX,1                  ; * 2        ticks per second.
  577.         ADD     AX,BX                 ; ( Accumulation = * 2.25 )
  578.         SHL     BX,1                  ; * 4        An approximation of
  579.         SHL     BX,1                  ; * 8        18.25 is used, rather
  580.         SHL     BX,1                  ; * 16       than actual 18.2.
  581.         ADD     AX,BX                 ; ( Accumulation = * 18.25 )
  582.         ADD     AX,152                ;Add in correction factors
  583.         ADD     AX,DX                 ;Add in hours result
  584.         MOV     ES:WHENLO,AX          ;completing tick value.
  585.  
  586.         ; Accept command tail, ready to enter after delay expires
  587.  
  588.         MOV     BX,OFFSET ES:WHCMD    ;Point to WHEN command buffer
  589. CMDCP:
  590.         CALL    GETCH                 ;If there is a character
  591.         JC      BADCM                 ;available, And:
  592.         CMP     AL,' '                ;It is an ASCII Space,
  593.         JNE     CMDC1                 ;Then: Throw it out, and
  594.         JMP    SHORT CMDCP            ;scan another.
  595.  
  596.         ; Report error in command string input
  597. BADCM:
  598.         MOV     AL,02H                ;Assign error level (this error)
  599.         MOV     DX,OFFSET CMDERR      ;Select time input error message
  600.         JMP     ERREX                 ;and exit with error display.
  601. CMDC1:
  602.         MOV     ES:[BX],AL            ;Put it into the command line
  603.         INC     BX                    ;step over it,
  604.         CALL    GETCH                 ;If there is another character
  605.         JNC     CMDC1                 ;available, continue, Else:
  606. CMDCX:
  607.         CMP     BX,ES:ISKIPO          ; Clear the rest of the buffer
  608.         JE      CMDCE
  609.         MOV     AL,0
  610.         MOV     ES:[BX],AL
  611.         INC     BX
  612.         JMP     CMDCX
  613.  
  614. CMDCE:
  615.         MOV     ES:BYTE PTR TIMEI+1,5 ;Start time monitor & wait.
  616.         MOV     TORG,5
  617.  
  618.         ; Report action if interactive, exit to DOS, no error.
  619.         ; (ISR handler remains installed as a resident.)
  620. EXIT:
  621.         MOV     AX,0
  622. EXIT_0: 
  623.         PUSH    AX
  624.         MOV     AL,TORG
  625.         MOV     ES:BYTE PTR TIMEI+1,AL ;Start time monitor from original value.
  626.         CALL    RPSTAT
  627.         CMP     RESIDENT, 0FFH ;TRUE
  628.         JE      EXIT_1
  629.  
  630.         ; Set up interrupt vector for timer (vector 08H *4)
  631. ;       release memory allocated to our environment segment
  632. ;
  633. ;       MOV     ES,CS:[2CH]            ; environment memory segment
  634. ;       MOV     AH,049H                ; give it back to system
  635. ;       INT     021H                   ;
  636.  
  637. ;
  638. ;       calculate our resident size rounded-up to the next paragraph
  639. ;
  640.         MOV     DX,OFFSET ENTES + 15   ; length of resident code
  641.         MOV     CL,4                   ; set (cl) to divide by
  642.         SHR     DX,CL                  ;   16 to get para count
  643.  
  644. ;
  645. ;       terminate and leave our resident routines in place
  646. ;
  647.         POP     AX
  648.         MOV     AH,031H                ; tsr op and return code
  649.         INT     021H                   ; terminate
  650. ;       MOV     ES,ENTES
  651. ;       MOV     DX,OFFSET TSREND
  652. ;       INT     27H
  653.  
  654. EXIT_1: MOV     AH,4CH
  655.         INT     21H
  656.  
  657.  
  658.  
  659.         ; Report error if interactive, exit to DOS with error level.
  660. ERREX:
  661.         PUSH    AX                    ;Save error level value.
  662.         MOV     AL,INTER              ;Consider interactive flag
  663.         CMP     AL,' '                ;If interactive with a user,
  664.         JNE     ERRE1                 ;Then:
  665.         MOV     AH,9                  ;Display the selected error
  666.         INT     21H                   ;message for him.
  667. ERRE1:
  668.         MOV     AL,INTER
  669.         CMP     AL,' '
  670.         JNE     ERRE2
  671.         MOV     DX,OFFSET ACTERR
  672.         MOV     AH,9
  673.         INT     21H
  674. ERRE2:
  675.         MOV     ES,ENTES              ;Restore entry PSP segment
  676.         POP     AX                    ;Use the specified error level
  677.         MOV     ES:BYTE PTR TIMEI+1,0 ;to inform DOS processes of
  678.                                       ;the error in WHEN and
  679.         MOV     TORG,0
  680.         JMP     EXIT_0                ;KILL this thing.
  681.                                       ;(Leave Resident Portion...)
  682. TIMERR  DB BELL
  683.         DB "Program Error  : "
  684.         DB "Time specified is in the wrong format. We don't know WHEN!",'$'
  685.  
  686. CMDERR  DB BELL
  687.         DB "Program Error  : "
  688.         DB "Command must be specified. We know WHEN, but not what to do!",'$'
  689.  
  690. ACTERR  DB CR,LF,BELL
  691.         DB "                 "
  692.         DB "All pending calls have been cancelled! Please try again!",CR,LF
  693.         DB "Command syntax : WHEN HH[:MM[:SS]] command [command tail]",CR,LF,'$'
  694.  
  695.         ; Decrement character count CCOUNT.  If it goes to 0, return
  696.         ; flag C = 1, and exit.  If there are characters available,
  697.         ; read a character from string pointed to by SI & step SI on.
  698.         ;
  699. GETCH   PROC    NEAR
  700.         DEC     CCOUNT                ;If there is a character
  701.         JS      GETCE                 ;Then:
  702.         MOV     AL,[SI]               ;Read a character,
  703.         INC     SI                    ;step over it,
  704.         CLC                           ;clear the carry flag
  705.         RET                           ;and return.
  706. GETCE:
  707.         XOR     AL,AL                 ;AL = 0, C = 0
  708.         CMC                           ;C = 1  (Report error)
  709.         RET
  710. GETCH   ENDP
  711.  
  712.  
  713.  
  714.         ; Check current contents of AL.  Value must be .GE. '0'
  715.         ; and .LE. than the upper limit specified in AH.  No data
  716.         ; is changed, but the result is returned in the C flag.
  717.         ; C = 0, AL is valid number.  C = 1, Error, AL is invalid.
  718.         ;
  719. CHNUM   PROC    NEAR
  720.         CMP     AL,AH                 ;If not above the limit
  721.         JA      CHNUE                 ;And:
  722.         CMP     AL,'0'                ;If ASCII 0 or greater,
  723.         JB      CHNUE                 ;Then:
  724.         RET                           ;Return, C = 0
  725. CHNUE:
  726.         STC                           ;Error has been seen,
  727.         RET                           ;Return, C = 1
  728. CHNUM   ENDP
  729.  
  730.  
  731.  
  732.         ; Convert 2 Asci digits (high order first) pointed to
  733.         ; by register BX, into equivalent binary in AX.
  734.         ;
  735. ASCBIN  PROC    NEAR
  736.         MOV     AL,ES:[BX]            ;Read high digit,
  737.         INC     BX                    ;step over it,
  738.         AND     AX,000FH              ;strip to binary, and
  739.         MOV     CL,10D                ;multiply it by 10.
  740.         MUL     CL
  741.         MOV     CL,ES:[BX]            ;Read the low digit
  742.         AND     CX,000FH              ;strip to binary, and
  743.         ADD     AX,CX                 ;add it in.
  744.         RET
  745. ASCBIN  ENDP
  746.  
  747.         ;report status of TSR
  748.         ;
  749. RPSTAT  PROC    NEAR
  750.         MOV     AL,INTER              ;Consider interactive flag
  751.         CMP     AL,' '                ;If interactive with a user,
  752.         JNE     RPST3                 ;Then:
  753.         MOV     DX,OFFSET WHRUN1      ;Format the screen, and
  754.         MOV     AH,9                  ;Display the details.
  755.         INT     21H
  756.         PUSH    DS
  757.         MOV     AX,ES
  758.         MOV     DS,AX
  759.         MOV     DX,OFFSET ES:HH10     ;Report the requested time,
  760.         MOV     AH,9                  ;expanding if required.
  761.         INT     21H
  762.         POP     DS
  763.  
  764.         MOV     DX,OFFSET WHRUN2      ;Format the screen, and
  765.         MOV     AH,9                  ;Display the details.
  766.         INT     21H
  767.         MOV     BX,OFFSET ES:WHCMD    ;Report the command to be run
  768.                                       ;at specified time, as entered.
  769. RPST1:
  770.         MOV     DL,ES:[BX]            ;Take a character from the
  771.         INC     BX                    ;command, and step over it.
  772.         OR      DL,DL                 ;If not a terminating NULL,
  773.         JZ      RPST2                 ;Then:
  774.         MOV     AH,2                  ;Display this character
  775.         INT     21H
  776.         JMP    SHORT RPST1            ;Continue with command string.
  777. RPST2:
  778.         CMP     TORG,0
  779.         JNE     TRPST1
  780.         MOV     DX,OFFSET INACTV
  781.         JMP     TRPST
  782. TRPST1: CMP     TORG,5
  783.         JNE     TRPST2
  784.         MOV     DX,OFFSET ACTIVE
  785.         JMP     TRPST
  786. TRPST2: MOV     DX,OFFSET WHOKNW
  787. TRPST:  MOV     AH,9
  788.         INT     21H
  789. RPST3:  RET
  790.  
  791. WHRUN1  DB       'At This Time   : $'
  792. WHRUN2  DB CR,LF,'Do This Command: $'
  793.         
  794. ACTIVE  DB CR,LF,'Current Status : *active*',CR,LF,CR,LF,'$'
  795. INACTV  DB CR,LF,'Current Status : *inactive*',CR,LF,CR,LF,'$'
  796. WHOKNW  DB CR,LF,'Current Status : *status unknown*',CR,LF,CR,LF,'$'
  797.  
  798. RPSTAT  ENDP
  799.  
  800. WHEN    ENDP
  801. CSEG    ENDS
  802.         END     WHEN
  803.